/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Team Fuzzballs
 * Philip Dilse, Keith McKinley, Rebecca Siegel
 */

import junit.framework.TestCase;

import java.util.Map;
import java.util.HashMap;
import java.util.Map.Entry;

import org.junit.Assert;

class errorString {
    private java.lang.String text;
    private int errorCount ;
    
    public errorString(java.lang.String inText) 
    {
            text = inText;
            errorCount = 0;
    }
    
    public java.lang.String getString()
    {
            return text;
    }
    public int getErrorCount()
    {
            return errorCount;
    }
    public void incrementErrorCounter()
    {
            errorCount ++;
    }
}

/**
 * Performs Validation Test for url validations.
 *
 * @version $Revision: 1128446 $ $Date: 2011-05-27 13:29:27 -0700 (Fri, 27 May 2011) $
 */
public class UrlValidatorTest extends TestCase {

   private boolean printStatus = false;
   private boolean printIndex = false;//print index that indicates current scheme,host,port,path, query test were using.

   public UrlValidatorTest(String testName) {
      super(testName);
   }

   public void testManualTest()
   {
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   System.out.println("Manual tests-----------------------------------------------------------------");
	   
	   // test schemes
	   String url = "http://www.amazon.com";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "3tp://www.amazon.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url);

	   // test authority
	   url = "http://www.amazon";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.amazon.c";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.amazon.c:123";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.amazon.com:123";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.amazon.com:1234";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);

	   // test path
	   url = "http://www.amazon.com//file";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.amazon.com/test1/file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   // test query
	   url = "http://www.amazon.com?userID=1";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.amazon.com?userID=1:name=bob";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);

	   // test fragment
	   url = "http://www.amazon.com#form";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);	   
   }
   
   // test partition between scheme and authority
   public void testYourFirstPartition()
   {
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   System.out.println("First Partition tests-----------------------------------------------------------------");
	   
	   // test various schemes with other URL components known to be valid
	   String url = "http://www.google.com";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http//www.google.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // no colon
	   
	   url = "ht3://www.google.com";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "HTTP://www.google.com";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "ftp/://www.google.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // slashes not allowed in scheme
	   
	   url = "4http://www.google.com"; 
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // first char must be letter
	   
	   url = "file:///path/to/file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   // boundary testing between scheme and authority
	   url = "//www.google.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // no scheme
	   
	   url = "/www.google.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // no scheme
	   
	   url = "www.google.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // valid in a browser but technically invalid
	   
	   url = "http:/www.google.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // only one slash
	   
	   url = "http:///www.google.com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // three slashes
	   
	   url = "file://path/to/file";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // file scheme needs three slashes
	   
	   // test on authority side of partition with known valid scheme
	   url = "http://google.com";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://com";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url);
   }
   
   // test partition between authority and path
   public void testYourSecondPartition(){
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   System.out.println("Second Partition tests-----------------------------------------------------------------");
	   
	   // test authority side of partition
	   String url = "http://www.google.com/";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.google.com:123/";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "file:///";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.google.c/";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // invalid top-level domain
	   
	   url = "http://www.google.c:123/";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // invalid top-level domain
	   
	   // test boundary between authority and path
	   url = "http://www.google.compath/to/file";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // missing slash between authority and path
	   
	   url = "http://www.google.com:123path/to/file";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // missing slash between authority and path
	   
	   url = "http://www.google.com/path/to/file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.google.com:123/path/to/file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "file:///path/to/file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "file:////path/to/file";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // one too many slashes
	   
	   url = "http://www.google.com//path/to/file";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // one too many slashes
	   
	   // test path side of partition
	   url = "http://www.google.com/path//to/file";
	   System.out.println("Expected=false Actual=" + urlVal.isValid(url) + " url=" + url); // two slashes in a row
	   
	   url = "http://www.google.com/../file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "file:///../file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "http://www.google.com/./file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
	   
	   url = "file:///./file";
	   System.out.println("Expected=true Actual=" + urlVal.isValid(url) + " url=" + url);
   }
   
   public void testIsValid()
   {
           errorString[] schemes = new errorString[9];
           schemes[0] = new errorString("http://");
           schemes[1] = new errorString("http:");
           schemes[2] = new errorString("ftp://");
           schemes[3] = new errorString(""); 
           schemes[4] = new errorString("https://");
           schemes[5] = new errorString("."); 
           schemes[6] = new errorString("file://"); 
           schemes[7] = new errorString("://"); 
           schemes[8] = new errorString("tftp://");
           //ArrayList schemes = new ArrayList();
           //schemes.add(new errorString("http://") );
           
           errorString hosts[] = new errorString[21];
           hosts[0] = new errorString("google.com");
           hosts[1] = new errorString("_billy_bob%.org");
           hosts[2] = new errorString("cnn.com");
           hosts[3] = new errorString("goo/gle.com");
           hosts[4] = new errorString("www.purple.com");
           hosts[5] = new errorString("cn n.com");
           hosts[6] = new errorString("amazon.com");
           hosts[7] = new errorString("bill%%y.org");
           hosts[8] = new errorString("jimbob.co:789");
           hosts[9] = new errorString("ama%1Hzon.com");
           hosts[10] = new errorString("www.catsNponies.co");
           hosts[11] = new errorString("www.google/.com");
           hosts[12] = new errorString("jimbo.co.nz");
           hosts[13] = new errorString("google.com:");
           hosts[14] = new errorString("google.co:12349");
           hosts[15] = new errorString("goo=gle.org");
           hosts[16] = new errorString("google.com:65535");
           hosts[17] = new errorString("123.456.789.4");
           hosts[18] = new errorString("123.001.255.4");
           hosts[19] = new errorString("2001:GFFF:1234:1234:1234:1234:1234:1234");
           hosts[20] = new errorString("2001:FFFF:1234:5678:90AB:CDEF:1123:4567");
           
           
           errorString paths[] = new errorString[12];
           paths[0] = new errorString("/software/htp/cics/in%dex.html");
           paths[1] = new errorString("/bob%%thorton");
           paths[2] = new errorString("/bobThorton.htm");
           paths[3] = new errorString("bob thorton.htm");
           paths[4] = new errorString("");
           paths[5] = new errorString("/meyer s.php");
           paths[6] = new errorString("/_bob/thorton");
           paths[7] = new errorString("bridgeport.txt");
           paths[8] = new errorString("/jimmy_fallon&seth.php");
           paths[9] = new errorString("/payton.htm%");
           paths[10] = new errorString("/bridge%2Fport.php");
           paths[11] = new errorString("/billy%*.php");
           
           errorString queries[] = new errorString[12];
           queries[0] = new errorString("");
           queries[1] = new errorString("?=bluebird");
           queries[2] = new errorString("?q=bluebird");
           queries[3] = new errorString("?%=bluebird");
           queries[4] = new errorString("?billy=72");
           queries[5] = new errorString("?!bob=jimmy");
           queries[6] = new errorString("?jimmy=fallon");
           queries[7] = new errorString("?q=*2Fg");
           queries[8] = new errorString("?jack=theRipper");
           queries[9] = new errorString("?10=bob");
           queries[10] = new errorString("?billy=42");
           queries[11] = new errorString("?pants = areCool");
           
           //int numTests = schemes.length + hosts.length + paths.length + queries.length; 
           int failedTests = 0;
           int successfulTests = 0;
           boolean noisyTest = true;
           java.lang.String curTest;
           boolean isValid = true;
           boolean resultIsValid;
           UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
           for(int schemeCounter = 0; schemeCounter<schemes.length; schemeCounter++) 
           {
                   for(int hostCounter = 0; hostCounter<hosts.length; hostCounter++)
                   {
                           for(int pathCounter = 0; pathCounter < paths.length; pathCounter++)
                           {
                                   for(int queryCounter = 0; queryCounter < queries.length; queryCounter++)
                                   {
                                           //assemble string to test
                                           curTest = null;
                                           curTest = schemes[schemeCounter].getString();
                                           curTest += hosts[hostCounter].getString();
                                           curTest += paths[pathCounter].getString();
                                           //System.out.println("Partial test:  " + curTest + ", queryCounter = " + queryCounter + "query= " + queries[queryCounter].getString());
                                           curTest += queries[queryCounter].getString();
                                           //System.out.println("Next test: " + curTest);
                                           if ( (schemeCounter % 2 == 0) && (hostCounter % 2 == 0) && 
                                                           (pathCounter % 2 == 0) && (queryCounter % 2 == 0) )
                                           {//test should be a valid url
                                                   isValid = true;
                                           } else
                                           {
                                                   isValid = false;
                                           }
                                           //carry out test
                                           resultIsValid = urlVal.isValid(curTest);
                                           
                                          //Assert result is as expected
                                           //Assert.assertEquals(resultIsValid, isValid);
                                           
                                           if (resultIsValid != isValid)
                                           {       //test didn't show the expected result.  log error
                                                   failedTests ++;
                                                   //if (schemeCounter % 2 == 0 )
                                                   if ( (schemeCounter % 2 == 0 && !(resultIsValid)) || (schemeCounter % 2 == 1 && resultIsValid) )
                                                           schemes[schemeCounter].incrementErrorCounter();
                                                   if ( (hostCounter % 2 == 0 && !(resultIsValid)) || (hostCounter % 2 ==  1 && resultIsValid) )
                                                           hosts[hostCounter].incrementErrorCounter();
                                                   if ( (pathCounter % 2 == 0 && !(resultIsValid)) || (pathCounter % 2 == 1 && resultIsValid) )
                                                           paths[pathCounter].incrementErrorCounter();
                                                   if ( (queryCounter % 2 == 0 && !(resultIsValid)) || (queryCounter % 2 == 1 && resultIsValid) )
                                                           queries[queryCounter].incrementErrorCounter();
                                                   if (noisyTest)
                                                   {
                                                           /*System.out.print("Test on url:  \"" + curTest + "\"  failed!, \n\tThis url is ");
                                                           if (isValid) 
                                                                   System.out.println("valid, but was called invalid.");
                                                           else
                                                                   System.out.println("invalid, but was called valid.");
                                                   */}
                                                  
                                           } else
                                           {
                                                   successfulTests ++;
                                                   //System.out.println("\n\nSuccessful *" + isValid + "* Test:  " + curTest + "\n\n");
                                           }
                                   }
                           }
                   }
           }
           System.out.println("successful: " + successfulTests + ", failed: " + failedTests);
           System.out.println("Scheme's errors:  ");
           for (int Counter = 0; Counter < schemes.length; Counter ++)
           {
                   System.out.print(schemes[Counter].getErrorCount() + ", ");
           }
           System.out.print("\n");
           System.out.println("Host's errors:  ");
           for (int Counter = 0; Counter < hosts.length; Counter ++)
           {
                   System.out.print(hosts[Counter].getErrorCount() + ", ");
           }
           System.out.print("\n");
           System.out.println("Path's errors:  ");
           for (int Counter = 0; Counter < paths.length; Counter ++)
           {
                   System.out.print(paths[Counter].getErrorCount() + ", ");
           }
           System.out.print("\n");
           System.out.println("Query's errors:  ");
           for (int Counter = 0; Counter < queries.length; Counter ++)
           {
                   System.out.print(queries[Counter].getErrorCount() + ", ");
           }
           System.out.print("\n");
           
   }
   
   public void testAnyOtherUnitTest()
   {
	   Map<String, Boolean> schemes = new HashMap<String, Boolean>();
	   schemes.put("http:", true);
	   schemes.put("http", false); // no colon
	   schemes.put("ht3:", true);
	   schemes.put("ftp/p:", false); // slashes not allowed
	   schemes.put("ftp:", true);
	   schemes.put("4http:", false); // only a-z for first character
	   schemes.put("foo+:", true);
	   
	   Map<String, Boolean> hostnames = new HashMap<String, Boolean>();
	   hostnames.put("//www.google.com", true);
	   hostnames.put("/www.google.com", false); // need two slashes at beginning
	   hostnames.put("//google.com", true);
	   hostnames.put("//10.10.10.10", true);
	   hostnames.put("//www.maps_google.com", false); // underscores not allowed
	   hostnames.put("www.google.com", false); // no leading slashes
	   hostnames.put("//www.google.c", false); // invalid domain
	   
	   Map<String, Boolean> ports = new HashMap<String, Boolean>();
	   ports.put("", true);
	   ports.put("123", false); // needs leading colon
	   ports.put(":123", true);
	   ports.put(":12345", true);
	   ports.put(":1234567", false); // only up to 5 digits allowed
	   ports.put(":12a", false); // no letters allowed
	   
	   Map<String, Boolean> paths = new HashMap<String, Boolean>();
	   paths.put("//path/to/file", false); // two slashes together not allowed
	   paths.put("/path/to/file", true);
	   paths.put("/../../file", true);
	   paths.put("/", true);
	   paths.put("path/to/file", false); // needs leading slash
	  
	   Map<String, Boolean> queries = new HashMap<String, Boolean>();
	   queries.put("", true);
	   queries.put("user=bob&id=1", true); 
	   queries.put("?user=bob", true);
	   queries.put("?user=bob;id=2", true);
	   
	   Map<String, Boolean> fragments = new HashMap<String, Boolean>();
	   fragments.put("#form", true);
	   fragments.put("#", true);
	   fragments.put("#form-id", true);
	   
	   int count = 0;
	   int errors = 0;
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   
	   for (Entry<String, Boolean> scheme : schemes.entrySet()) {
		   boolean expected1 = scheme.getValue();
		   
		   for (Entry<String, Boolean> hostname : hostnames.entrySet()) {
			   boolean expected2 = hostname.getValue();
			   
			   for (Entry<String, Boolean> port : ports.entrySet()) {
				   boolean expected3 = port.getValue();
				   
				   for (Entry<String, Boolean> path : paths.entrySet()) {
					   boolean expected4 = path.getValue();
					   
					   for (Entry<String, Boolean> query : queries.entrySet()) {
						   boolean expected5 = query.getValue();
						   
						   for (Entry<String, Boolean> fragment : fragments.entrySet()) {
							   boolean expected6 = fragment.getValue();
							   String url = scheme.getKey() + hostname.getKey() + port.getKey() + path.getKey() + query.getKey() + fragment.getKey();
							   boolean expected = expected1 & expected2 & expected3 & expected4 & expected5 & expected6;
							   boolean actual = urlVal.isValid(url);
							   
							   if (actual != expected) {
								   System.out.println("actual=" + actual + " expected=" + expected + " " + url);
								   errors++;
							   }
							   count++;		   
						   }
					   }
				   }
			   }
		   }
	   }
	   System.out.println("Count=" + count + " errors=" + errors);
   }
   /**
    * Create set of tests by taking the testUrlXXX arrays and
    * running through all possible permutations of their combinations.
    *
    * @param testObjects Used to create a url.
    */
   

}
